#region License, Terms and Conditions
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
#endregion
using System;
using Pesta.Libraries.OAuth;

namespace raya.Library.OAuth
{
    class OAuthServer
    {
        readonly IOAuthDataStore data_store;

        public OAuthServer()
        {
            data_store = RayaOAuthDataStore.Instance;
        }
        public OAuthServer(IOAuthDataStore data_store)
        {
            this.data_store = data_store;
        }

        // high level functions


        /**
    * process a request_token request
    * returns the request token on success
    */
        public OAuthToken fetch_request_token(OAuthRequest _request, OAuthMessage message)
        {
            OAuthConsumer consumer = get_consumer(_request);
            OAuthAccessor accessor = new OAuthAccessor(consumer);
            SimpleOAuthValidator validator = new SimpleOAuthValidator();
            try
            {
                validator.validateMessage(message, accessor);
            }
            catch (Exception)
            {
                return null;
            }

            OAuthToken _new_token = data_store.new_request_token(consumer);

            return _new_token;
        }

        /**
    * process an access_token request
    * returns the access token on success
    */
        public OAuthToken fetch_access_token(OAuthRequest _request, OAuthMessage message)
        {
            OAuthConsumer consumer = get_consumer(_request);

            // requires authorized request token
            OAuthToken _token = get_token(_request, consumer, "request");
            OAuthAccessor accessor = new OAuthAccessor(consumer);
            accessor.TokenSecret = _token.secret;
            SimpleOAuthValidator validator = new SimpleOAuthValidator();
            try
            {
                validator.validateMessage(message, accessor);
            }
            catch (Exception)
            {
                return null;
            }
            OAuthToken _new_token = data_store.new_access_token(_token, consumer);

            return _new_token;
        }

        /**
    * verify an api call, checks all the _parameters
    */
        public OAuthToken[] verify_request(OAuthRequest _request, OAuthMessage message) 
        {
            OAuthConsumer consumer = get_consumer(_request);
            OAuthToken _token = get_token(_request, consumer, "access");
            OAuthAccessor accessor = new OAuthAccessor(consumer);
            SimpleOAuthValidator validator = new SimpleOAuthValidator();
            try
            {
                validator.validateMessage(message, accessor);
            }
            catch (Exception)
            {
                return null;
            }
            return new[] { new OAuthToken(consumer.consumerKey, consumer.consumerSecret), _token };
        }

        // Internals from here
        /**
    * try to find the consumer for the provided request's consumer key
    */

        public OAuthConsumer get_consumer(OAuthRequest _request)
        {
            string _consumer_key = _request.get_parameter("oauth_consumer_key");
            if (String.IsNullOrEmpty(_consumer_key))
            {
                throw new OAuthException("Invalid consumer key");
            }

            OAuthConsumer _consumer = data_store.lookup_consumer(_consumer_key);
            if (_consumer == null)
            {
                throw new OAuthException("Invalid consumer");
            }

            return _consumer;
        }

        /**
    * try to find the token for the provided request's token key
    */
        private OAuthToken get_token(OAuthRequest _request, OAuthConsumer _consumer)
        {
            return get_token(_request, _consumer, "access");
        }

        private OAuthToken get_token(OAuthRequest _request, OAuthConsumer _consumer, string _token_type)
        {
            string _token_field = _request.get_parameter("oauth_token");
            OAuthToken _token = data_store.lookup_token(_consumer, _token_type, _token_field);
            if (_token == null)
            {
                throw new OAuthException("Invalid _token_type token: _token_field");
            }
            return _token;
        }
    }
}

